/*完成日志器模块
    1. 抽象日志基类
    2. 派生出不同的子类(同步日志器类 & 异步日志器类)
*/
#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name,
               LogLevel::value level,
               Formatter::ptr &formatter,
               std::vector<LogSink::ptr> &sinks) : _logger_name(logger_name),
                                                   _limit_level(level),
                                                   _formatter(formatter),
                                                   _sinks(sinks.begin(), sinks.end()) {}
        const std::string &name()
        {
            return _logger_name;
        }
        /*完成日志消息对象过程初始化，得到初始化的日志消息字符串-- 然后进行落地输出*/
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (LogLevel::value::DEBUG < _limit_level)
            {
                return;
            }
            // 2. 对fmt格式化字符串和不定参进行字符串组织,得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed!\n";
                return;
            }
            va_end(ap); // 将ap指针置空
            serialize(LogLevel::value::DEBUG, file, line, res);
            free(res);
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (LogLevel::value::INFO < _limit_level)
            {
                return;
            }
            // 2. 对fmt格式化字符串和不定参进行字符串组织,得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed!\n";
                return;
            }
            va_end(ap); // 将ap指针置空
            serialize(LogLevel::value::INFO, file, line, res);
            free(res);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (LogLevel::value::WARN < _limit_level)
            {
                return;
            }
            // 2. 对fmt格式化字符串和不定参进行字符串组织,得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed!\n";
                return;
            }
            va_end(ap); // 将ap指针置空
            serialize(LogLevel::value::WARN, file, line, res);
            free(res);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (LogLevel::value::ERROR < _limit_level)
            {
                return;
            }
            // 2. 对fmt格式化字符串和不定参进行字符串组织,得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed!\n";
                return;
            }
            va_end(ap); // 将ap指针置空
            serialize(LogLevel::value::ERROR, file, line, res);
            free(res);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (LogLevel::value::FATAL < _limit_level)
            {
                return;
            }
            // 2. 对fmt格式化字符串和不定参进行字符串组织,得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed!\n";
                return;
            }
            va_end(ap); // 将ap指针置空
            serialize(LogLevel::value::FATAL, file, line, res);
            free(res);
        }

    protected:
        void serialize(LogLevel::value level, const std::string &file, size_t &line, char *str)
        {
            // 3. 构造LogMsg对象
            LogMessage msg(level, line, file, _logger_name, str);
            // 4. 通过格式化工具对LogMsg进行格式化,得到格式化后的字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5. 进行落地输出
            log(ss.str().c_str(), ss.str().size());
        }

        // 抽象接口实现不同方式的落地输出
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level; // 当前日志等级
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,
                   LogLevel::value level,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> &sinks) : Logger(logger_name, level, formatter, sinks) {}

    protected:
        // 同步日志器将日志消息通过句柄进行落地
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return; // 落地为空说明日志消息未达到要求,无需落地
            for (auto &sink : _sinks)
            {
                sink->log(data, len); // 通过多态特性实现向不同的方向实现落地输出
            }
        }
    };

    // 异步日志器
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name,
                    LogLevel::value level,
                    Formatter::ptr &formatter,
                    std::vector<LogSink::ptr> &sinks,
                    AsyncType looper_type) : Logger(logger_name, level, formatter, sinks),
                                             _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type)) {}
        // 将数据写入缓冲区
        void log(const char *data, size_t len)
        {
            _looper->push(data, len);
        }
        // 实际进行将日志落地的函数
        void realLog(Buffer &buf) // 成员函数的参数默认包含this指针
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper; // 需要回调函数及是否完全版本的类型
    };

    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 使用建造者模式建造日志器,降低用户使用成本
    // 1. 抽象日志器建造者类(完成日志器对象所需零部件的构建&日志器构建)
    //       1. 设置日志器类型
    //       2. 将不同类型日志器的创建放在同一个日志器建造者类中完成
    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),
                          _limit_level(LogLevel::value::DEBUG),
                          _looper_type(AsyncType::ASYNC_SAFE) {}
        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void buildEnableUnSafeAsync()
        {
            _looper_type = AsyncType::ASUNC_UNSAFE;
        }
        void buildLoggerName(const std::string &name)
        {
            _logger_name = name;
        }
        void buildLoggerLevel(LogLevel::value level)
        {
            _limit_level = level;
        }
        void buildLoggerFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr sink = SinkFactor::create<SinkType>(std::forward<Args>(args)...); // 日志消息改落地:日志落地的指针
            _sinks.push_back(sink);
        }
        virtual Logger::ptr build() = 0; // 功能:最终完成不同的日志器函数
    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::value _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    // 派生出具体的建造类
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false);
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // 异步日志器
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                // 同步日志器
                return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
        }
    };


    // 日志管理器,使用单例模式
    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            // C++11后,对于静态局部变量,编译器在编译层面实现线程安全
            static LoggerManager eton;
            return eton;
        }
        // 添加任意类型日志器
        void addLogger(Logger::ptr &logger)
        {
            if (hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }
        // 判断有无该日志器
        bool hasLogger(const std::string &name)
        {
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }

            return true;
        }
        // 返回name指向的日志器对象的指针
        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }

            return it->second;
        }
        // 返回指向标准输出的日志器指针
        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        // 构造函数私有化,防止外界构造该日志管理器
        LoggerManager()
        {
            std::unique_ptr<log::LoggerBuilder> builder(new log::LocalLoggerBuilder);
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root", _root_logger)); // 防止外界进行修改
        }

    private:
        std::mutex _mutex;                                     // 互斥锁
        Logger::ptr _root_logger;                              // 默认日志器,用于向标准输出打印
        std::unordered_map<std::string, Logger::ptr> _loggers; // 管理日志器的哈希表
    };

    // 设计一个全局日志器建造者
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false);
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // 异步日志器
                logger =  std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                // 同步日志器
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif